using System;
using System.Drawing.Design;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Windows.Forms;
using Microsoft.Practices.Common;
using System.ComponentModel.Design;
using Microsoft.Practices.ComponentModel;
using System.Collections;
using System.Globalization;
using System.Security.Permissions;

namespace VSSDKAssist.Assets.Editors
{
	/// <summary>
	/// Editor that will choose a file when it is used
	/// It has properties that can be overrided 
	/// to use different filter, title and initialdirectory
	/// </summary>
	[ServiceDependency(typeof(IDictionaryService))]
	public class FileChooserEditor : UITypeEditor, IAttributesConfigurable, IDisposable
	{
		private string title;
		private string filter;
		private string initialDirectory;
		private OpenFileDialog openFileDialog;
		private const string DEFAULT_START_LOCATION = @"C:\";
		private bool disposed;

		/// <summary>
		/// Initializes a new instance of the <see cref="T:FileChooser"/> class.
		/// </summary>
		public FileChooserEditor()
		{
		}

		/// <summary>
		/// Edits the value.
		/// </summary>
		/// <param name="context">The context.</param>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="value">The value.</param>
		/// <returns></returns>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1725:ParameterNamesShouldMatchBaseDeclaration", MessageId = "1#"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1818:DoNotConcatenateStringsInsideLoops"), PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
		public override object EditValue(ITypeDescriptorContext context, IServiceProvider serviceProvider, object value)
		{
			if(serviceProvider != null)
			{
				IWindowsFormsEditorService service = (IWindowsFormsEditorService)serviceProvider.GetService(typeof(IWindowsFormsEditorService));
				if(service == null)
				{
					return value;
				}

				this.openFileDialog = new OpenFileDialog();
				this.openFileDialog.Multiselect = true;
				this.InitializeDialog(this.openFileDialog);

				String filename = value as string;

				if(filename != null)
				{
					if(!filename.Contains("\""))
					{
						this.openFileDialog.FileName = filename;
					}
					else
					{
						this.openFileDialog.FileName = String.Empty;
					}
				}

				if(this.openFileDialog.ShowDialog() == DialogResult.OK)
				{
					if(this.openFileDialog.FileNames != null && this.openFileDialog.FileNames.Length > 1)
					{
						String files = String.Empty;
						foreach(String str in this.openFileDialog.FileNames)
						{
							files = string.Concat(files,"\"",str,"\" ");
						}
						StringInfo si = new StringInfo(files);
						value = si.SubstringByTextElements(0, si.LengthInTextElements - 1);
					}
					else
					{
						value = this.openFileDialog.FileName;
					}
				}
			}

			return value;
		}

		/// <summary>
		/// Gets the editor style used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"></see> method.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that can be used to gain additional context information.</param>
		/// <returns>
		/// A <see cref="T:System.Drawing.Design.UITypeEditorEditStyle"></see> value that indicates the style of editor used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"></see> method. If the <see cref="T:System.Drawing.Design.UITypeEditor"></see> does not support this method, then <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"></see> will return <see cref="F:System.Drawing.Design.UITypeEditorEditStyle.None"></see>.
		/// </returns>
		[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
		public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
		{
			return UITypeEditorEditStyle.Modal;
		}

		/// <summary>
		/// Initializes the dialog.
		/// </summary>
		/// <param name="dialog">The dialog.</param>
		private void InitializeDialog(OpenFileDialog dialog)
		{
			if(String.IsNullOrEmpty(title))
			{
				this.title = Properties.Resources.DefaultFileChooserTitle;
			}

			if(String.IsNullOrEmpty(filter))
			{
				this.filter = Properties.Resources.DefaultFilterExpression;
			}

			if(String.IsNullOrEmpty(initialDirectory))
			{
				this.initialDirectory = DEFAULT_START_LOCATION;
			}

			dialog.InitialDirectory = this.initialDirectory;
			dialog.Title = this.title;
			dialog.Filter = this.filter;
		}

		#region IAttributesConfigurable Members

		/// <summary>
		/// Configures the component using the dictionary of attributes specified
		/// in the configuration file.
		/// </summary>
		/// <param name="attributes">The attributes in the configuration element.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public void Configure(System.Collections.Specialized.StringDictionary attributes)
		{
			if(attributes.ContainsKey("Title"))
			{
				title = attributes["Title"];
			}

			if(attributes.ContainsKey("Filter"))
			{
				filter = attributes["Filter"];
			}

			if(attributes.ContainsKey("InitialDirectory"))
			{
				initialDirectory = attributes["InitialDirectory"];
			}
		}
		#endregion

		#region IDisposable Members
		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Disposes the specified disposing.
		/// </summary>
		/// <param name="disposing">if set to <c>true</c> [disposing].</param>
		protected virtual void Dispose(bool disposing)
		{
			if(!this.disposed)
			{
				if(disposing)
				{
					this.openFileDialog.Dispose();
				}
			}
			disposed = true;
		}

		/// <summary>
		/// Releases unmanaged resources and performs other cleanup operations before the
		/// <see cref="FileChooserEditor"/> is reclaimed by garbage collection.
		/// </summary>
		~FileChooserEditor()
		{
			Dispose(false);
		}
		#endregion
	}
}
